/*
 *  Copyright (c) 2019 by flomesh.io
 *
 *  Unless prior written consent has been obtained from the copyright
 *  owner, the following shall not be allowed.
 *
 *  1. The distribution of any source codes, header files, make files,
 *     or libraries of the software.
 *
 *  2. Disclosure of any source codes pertaining to the software to any
 *     additional parties.
 *
 *  3. Alteration or removal of any notices in or on the software or
 *     within the documentation included within the software.
 *
 *  ALL SOURCE CODE AS WELL AS ALL DOCUMENTATION INCLUDED WITH THIS
 *  SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION, WITHOUT WARRANTY OF ANY
 *  KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 *  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 *  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 *  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef API_TIMEOUT_HPP
#define API_TIMEOUT_HPP

#include "pjs/pjs.hpp"
#include "timer.hpp"
#include "list.hpp"

namespace pipy {

//
// Timeout
//

class Timeout : public pjs::ObjectTemplate<Timeout> {
public:
  auto wait() -> pjs::Promise*;
  void restart();
  void restart(double t);
  void cancel();

private:
  Timeout(double t);
  ~Timeout();

  enum State {
    PENDING,
    TIMEOUT,
    CANCELED,
  };

  struct Waiter :
    public pjs::Pooled<Waiter>,
    public List<Waiter>::Item
  {
    pjs::Ref<pjs::Promise::Settler> settler;
  };

  double m_duration;
  Timer m_timer;
  List<Waiter> m_waiters;
  State m_state = PENDING;
  bool m_scheduled = false;

  void schedule();
  void on_timeout();
  void notify_waiters();

  friend class pjs::ObjectTemplate<Timeout>;
};

} // namespace pipy

#endif // API_TIMEOUT_HPP
